home *** CD-ROM | disk | FTP | other *** search
Wrap
/* File: main.c Abstract: A skeleton of modern nib-based and Carbon Events-based Carbon application. AppleScriptRunner contains a folder within its application bundle, "AppleScripts" which contains a number of AppleScripts. AppleScriptRunner builds a popup menu populated with the AppleScript names. When "Execute" is clicked, the selected AppleScript is executed passing it one Text parameter, the contents of out HITextView. In this example all AppleScripts must take one, and only one, text parameter. An advisable method of adding functionallity to an application to send email is to create an AppleScript to send email, and then envoke the script from the application. In this example "Entourage" and "Mail" each send email, provided the email clients are correctly configured. The format of the HITextView to send mail should be: "Santa@NorthPole.com Dear Santa, My chimney ..." Because this sample requires only one input parameter, the AppleScrips themselves parse the "To" email address out as the first word, and assume the rest is the message body. The main entry to the "interesting" portion of the code is the routine: RunAppleScript(). Version: 1.0 Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. ("Apple") in consideration of your agreement to the following terms, and your use, installation, modification or redistribution of this Apple software constitutes acceptance of these terms. If you do not agree with these terms, please do not use, install, modify or redistribute this Apple software. In consideration of your agreement to abide by the following terms, and subject to these terms, Apple grants you a personal, non-exclusive license, under Apple's copyrights in this original Apple software (the "Apple Software"), to use, reproduce, modify and redistribute the Apple Software, with or without modifications, in source and/or binary forms; provided that if you redistribute the Apple Software in its entirety and without modifications, you must retain this notice and the following text and disclaimers in all such redistributions of the Apple Software. Neither the name, trademarks, service marks or logos of Apple Computer, Inc. may be used to endorse or promote products derived from the Apple Software without specific prior written permission from Apple. Except as expressly stated in this notice, no other rights or licenses, express or implied, are granted by Apple herein, including but not limited to any patent rights that may be infringed by your derivative works or by other works in which the Apple Software may be incorporated. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Copyright © 2005 Apple Computer, Inc., All Rights Reserved */ #include <Carbon/Carbon.h> #include <sys/param.h> struct GlobalAppInfo // Application globals { IBNibRef mainNibRef; }; typedef struct GlobalAppInfo GlobalAppInfo; static void SendCommandProcessEvent( UInt32 commandID ); static OSStatus GetControlBySigAndID( WindowRef window, OSType signature, SInt32 id, ControlRef *control ); static void InstallAppleEventHandlers( void ); static void DoPreferences( void ); static OSStatus DoSomething(); static OSStatus NavOpenDocument(); static pascal Boolean NavOpenFilterProc( AEDesc *theItem, void *info, NavCallBackUserData callBackUD, NavFilterModes filterMode ); static OSStatus HIViewFindBySigAndID( HIViewRef inStartView, OSType signature, SInt32 id, HIViewRef *outControl ); static TXNObject GetTXNObjectBySigAndID( WindowRef window, OSType signature, SInt32 id ); static void Wprintf( WindowRef window, char const *fmt, ... ); static OSStatus DisplayTextFileInWindow( WindowRef window, FSRef *fsRef ); static pascal OSStatus CommandProcessEventHandler( EventHandlerCallRef nextHandler, EventRef inEvent, void *userData ); // Added kHICommandRevert, kHICommandPageSetup, and kHICommandPrint static OSStatus OpenDocuments( AEDescList docList ); // Open Text files static OSStatus RunAppleScript( FSRef *scriptFSRef, char *textParameter ); static OSStatus GetAppleScriptsFolderFSRef( FSRef *fsRef); static OSStatus CreateMessageEvent( AppleEvent *theEvent, char *parameter ); static pascal OSStatus MainWindowEventHandler( EventHandlerCallRef nextHandler, EventRef inEvent, void *userData ); static OSStatus DoNewWindow( WindowRef *window ); // Install Event Handler for Text view GlobalAppInfo g; #pragma mark - #pragma mark • Main • int main( int argc, char *argv[] ) { OSStatus status; long response; const EventTypeSpec commandProcessEvents[] = { { kEventClassCommand, kEventCommandProcess } }; BlockZero( &g, sizeof(g) ); status = Gestalt( gestaltSystemVersion, &response ); if ( ! ((status == noErr) && (response >= 0x00001030)) ) // We require Mac OS X 10.3 or greater to run { DialogRef alertDialod; CreateStandardAlert( kAlertStopAlert, CFSTR("Mac OS X 10.3 (minimum) is required for this application"), NULL, NULL, &alertDialod ); RunStandardAlert( alertDialod, NULL, NULL ); ExitToShell(); } // Create a Nib reference passing the name of the nib file (without the .nib extension) CreateNibReference only searches into the application bundle. status = CreateNibReference( CFSTR("main"), &g.mainNibRef ); require_noerr( status, CantGetNibRef ); // Once the nib reference is created, set the menu bar. "MainMenu" is the name of the menu bar object. This name is set in InterfaceBuilder when the nib is created. status = SetMenuBarFromNib( g.mainNibRef, CFSTR("MenuBar") ); require_noerr( status, CantSetMenuBar ); EnableMenuCommand( NULL, kHICommandPreferences ); // Enable Preferences menu item InstallAppleEventHandlers(); InstallApplicationEventHandler( NewEventHandlerUPP(CommandProcessEventHandler), GetEventTypeCount(commandProcessEvents), commandProcessEvents, NULL, NULL ); RunApplicationEventLoop(); // Call the event loop CantSetMenuBar: CantGetNibRef: return( status ); } #pragma mark - #pragma mark • AppleEvent Handlers • static pascal OSErr HandleAppleEventOapp( const AppleEvent *theAppleEvent, AppleEvent *reply, long handlerRefcon ) { SendCommandProcessEvent( kHICommandNew ); // Instantiate an empty window at the beginning so the User sees something return( noErr ); } static pascal OSErr HandleAppleEventRapp( const AppleEvent *theAppleEvent, AppleEvent *reply, long handlerRefcon ) { WindowRef window = GetFrontWindowOfClass( kDocumentWindowClass, true ); if ( window == NULL ) SendCommandProcessEvent( kHICommandNew ); // We were already running but with no windows so we create an empty one. return( noErr ); } static pascal OSErr HandleAppleEventOdoc( const AppleEvent *theAppleEvent, AppleEvent *reply, long handlerRefcon ) { AEDescList docList; OSErr err = AEGetParamDesc( theAppleEvent, keyDirectObject, typeAEList, &docList ); require_noerr( err, CantGetDocList ); err = OpenDocuments( docList ); AEDisposeDesc( &docList ); CantGetDocList: return( err ); } static pascal OSErr HandleAppleEventPdoc( const AppleEvent *theAppleEvent, AppleEvent *reply, long handlerRefcon ) { return( errAEEventNotHandled ); } static void InstallAppleEventHandlers( void ) { OSErr status; status = AEInstallEventHandler( kCoreEventClass, kAEOpenApplication, NewAEEventHandlerUPP(HandleAppleEventOapp), 0, false ); require_noerr( status, CantInstallAppleEventHandler ); status = AEInstallEventHandler( kCoreEventClass, kAEReopenApplication, NewAEEventHandlerUPP(HandleAppleEventRapp), 0, false ); require_noerr( status, CantInstallAppleEventHandler ); status = AEInstallEventHandler( kCoreEventClass, kAEOpenDocuments, NewAEEventHandlerUPP(HandleAppleEventOdoc), 0, false ); require_noerr( status, CantInstallAppleEventHandler ); status = AEInstallEventHandler( kCoreEventClass, kAEPrintDocuments, NewAEEventHandlerUPP(HandleAppleEventPdoc), 0, false ); require_noerr( status, CantInstallAppleEventHandler ); // Note: Since RunApplicationEventLoop installs a Quit AE Handler, there is no need to do it here. CantInstallAppleEventHandler: return; } #pragma mark - #pragma mark • CarbonEvent Handlers • static pascal OSStatus CommandProcessEventHandler( EventHandlerCallRef nextHandler, EventRef inEvent, void *userData ) { HICommand command; UInt32 secs; DateTimeRec date; OSStatus status = eventNotHandledErr; TXNObject txnObject = GetTXNObjectBySigAndID( GetFrontWindowOfClass(kDocumentWindowClass, true), 'HITv', 0 ); GetEventParameter( inEvent, kEventParamDirectObject, typeHICommand, NULL, sizeof(HICommand), NULL, &command ); switch ( command.commandID ) { case kHICommandNew: status = DoNewWindow( NULL ); GetDateTime( &secs ); // Demonstrate how to use utility routine Wprintf SecondsToDate( secs, &date ); Wprintf( GetFrontWindowOfClass(kDocumentWindowClass, true), "Todays Date: %d/%d/%d\n", date.month, date.day, date.year ); break; case kHICommandOpen: status = NavOpenDocument(); break; case kHICommandPreferences: DoPreferences(); break; case kHICommandRevert: if ( txnObject != NULL ) status = TXNRevert( txnObject ); break; case kHICommandPageSetup: if ( txnObject != NULL ) status = TXNPageSetup( txnObject ); status = noErr; break; case kHICommandPrint: if ( txnObject != NULL ) status = TXNPrint( txnObject ); status = noErr; break; case 'DoIt': // Our own menu to hook in and Do Something... status = DoSomething(); break; } return( status ); } static pascal OSStatus MainWindowEventHandler( EventHandlerCallRef nextHandler, EventRef inEvent, void *inUserData ) { #pragma unused ( inCallRef ) HICommand command; OSStatus status = eventNotHandledErr; UInt32 eventKind = GetEventKind( inEvent ); UInt32 eventClass = GetEventClass( inEvent ); WindowRef window = (WindowRef) inUserData; switch ( eventClass ) { case kEventClassWindow: //if ( eventKind == kEventWindowClose ) // Dispose extra window storage here break; case kEventClassCommand: if ( eventKind == kEventCommandProcess ) { GetEventParameter( inEvent, kEventParamDirectObject, typeHICommand, NULL, sizeof(HICommand), NULL, &command ); if ( command.commandID == kHICommandOK ) // OK (Execute) Button was clicked in window { FSRef parentFSRef; FSRef fsRef; TXNObject txnObject; CFStringRef cfString; HFSUniStr255 appleScriptName; ControlRef control; SInt32 controlValue; MenuRef menuRef; Handle txnDataHandle = NULL; // Get the text to pass as a parameter to the AppleScript txnObject = GetTXNObjectBySigAndID( window, 'HITv', 0 ); // Get the TXNObject status = TXNGetDataEncoded( txnObject, kTXNStartOffset, kTXNEndOffset, &txnDataHandle, kTXNTextData ); // Retrieve the text. kTXNTextData specifies Text, not Unicode or Rich Text // Find the name of the chosen menu item, which is the name of our AppleScript to run status = GetControlBySigAndID( window, 'PopM', 0, &control ); // Get the popup menu control controlValue = GetControl32BitValue( control ); // Get the control value, which is the selected menu item menuRef = GetControlPopupMenuHandle( control ); // Get the MenuRef from the control CopyMenuItemTextAsCFString( menuRef, controlValue, &cfString ); // Copy the selected item text into a CFString // Convert our CFString to an HFSUniStr255 and create an FSRef to our chosen AppleScript appleScriptName.length = CFStringGetBytes( cfString, CFRangeMake(0, MIN(CFStringGetLength(cfString), 255)), kCFStringEncodingUnicode, 0, false, (UInt8 *)(appleScriptName.unicode), 255, NULL ); status = GetAppleScriptsFolderFSRef( &parentFSRef ); // Get FSRef to AppleScripts folder status = FSMakeFSRefUnicode( &parentFSRef, appleScriptName.length, appleScriptName.unicode, kTextEncodingUnknown, &fsRef ); // FSMakeFSRefUnicode to make FSRef to the selected AppleScript // Run the AppleScript passing in our text as a parameter status = RunAppleScript( &fsRef, *txnDataHandle ); // Release what we have allocated if ( cfString != NULL ) CFRelease( cfString ); if ( txnDataHandle != NULL ) DisposeHandle( txnDataHandle ); } } break; } return( status ); } #pragma mark - #pragma mark • Windows • static void DoPreferences( void ) { // Entry point for a preferences window DialogRef theAlert; CreateStandardAlert( kAlertStopAlert, CFSTR("No Preferences yet!"), NULL, NULL, &theAlert ); RunStandardAlert( theAlert, NULL, NULL ); } static OSStatus DoNewWindow( WindowRef *outWindow ) { OSStatus status; static EventHandlerUPP windowEventHandlerUPP; const EventTypeSpec windowEvents[] = { { kEventClassCommand, kEventCommandProcess }, { kEventClassWindow, kEventWindowClose } }; WindowRef window = NULL; // Create a window. "MainWindow" is the name of the window object. This name is set in InterfaceBuilder when the nib is created. status = CreateWindowFromNib( g.mainNibRef, CFSTR("MainWindow"), &window ); require_noerr( status, CantCreateWindow ); if ( windowEventHandlerUPP == NULL ) windowEventHandlerUPP = NewEventHandlerUPP( MainWindowEventHandler ); status = InstallWindowEventHandler( window, windowEventHandlerUPP, GetEventTypeCount(windowEvents), windowEvents, window, NULL ); require_noerr( status, CantInstallWindowEventHandler ); { FSIterator iterator; ItemCount actualObjects; FSRef fsRefs[32]; // Allow up to 32 FSRefs, in this case 32 AppleScripts FSRef fsRef; CFStringRef cfString; ControlRef control; int i; MenuRef menuRef; status = GetAppleScriptsFolderFSRef( &fsRef ); // Locate our AppleScripts folder within our application bundle status = FSOpenIterator( &fsRef, kFSIterateFlat, &iterator ); // Read the first 32 items of the "AppleScripts" folder using FSOpenIterator-FSGetCatalogInfoBulk-FSCloseIterator require_noerr( status, FileSystemError ); status = FSGetCatalogInfoBulk( iterator, 32, &actualObjects, NULL, 0, NULL, fsRefs, NULL, NULL ); status = FSCloseIterator( iterator ); if ( actualObjects > 0 ) // If we found some items { status = GetControlBySigAndID( window, 'PopM', 0, &control ); // Get the popup menu control menuRef = GetControlPopupMenuHandle( control ); // Get the MenuRef from the control SetControl32BitMaximum( control, actualObjects ); // Need to SetControl32BitMaximum for popups to function as expected DeleteMenuItem( menuRef, 1 ); // Delete the first menuItem titled: "No AppleScripts Found" for ( i = 0 ; i < actualObjects ; i++ ) // Itterate over the files we found { status = LSCopyDisplayNameForRef( &fsRefs[i], &cfString ); // Get the name of the file the Finder displays (may not include file extension) CFShow( cfString ); if ( (status == noErr) && ( ( CFStringHasPrefix( cfString, CFSTR(".") ) ) == false ) ) // Don't add ".DS_Store", or any other file starting with a "." AppendMenuItemTextWithCFString( menuRef, cfString, 0, NULL, NULL ); // Append the CFString of the AppleScript to out popup menu } } } // The window was created hidden so show it if the window parameter is NULL, if it's not, it will be the responsibility of the caller to show it. if ( outWindow == NULL ) ShowWindow( window ); SetWindowModified( window, false ); FileSystemError: CantInstallWindowEventHandler: CantCreateWindow: if ( outWindow != NULL ) *outWindow = window; return( status ); } #pragma mark - #pragma mark • Save/Open Document • static OSStatus NavOpenDocument() { OSStatus status; NavDialogCreationOptions options; NavReplyRecord navReply; static NavObjectFilterUPP navFilterUPP; NavDialogRef navDialog = NULL; status = NavGetDefaultDialogCreationOptions( &options ); require_noerr( status, CantGetDefaultOptions ); if ( navFilterUPP == NULL ) navFilterUPP = NewNavObjectFilterUPP( NavOpenFilterProc ); // Filter only documents we can open status = NavCreateChooseFileDialog( &options, NULL, NULL, NULL, navFilterUPP, NULL, &navDialog ); require_noerr( status, CantCreateDialog ); status = NavDialogRun( navDialog ); require_noerr( status, CantRunDialog ); status = NavDialogGetReply( navDialog, &navReply ); require( (status == noErr) || (status == userCanceledErr), CantGetReply ); if ( navReply.validRecord ) status = OpenDocuments( navReply.selection ); else status = userCanceledErr; NavDisposeReply( &navReply ); CantGetReply: CantRunDialog: if ( navDialog != NULL ) NavDialogDispose( navDialog ); CantCreateDialog: CantGetDefaultOptions: return( status ); } // Generic Navigation Services filter proc described in TechNote 2017, "Using Launch Services" // This filter querries LaunchServices to ask what types of documents this application can open. // Openable document types are defined within the applications info.plist file. static pascal Boolean NavOpenFilterProc( AEDesc *theItem, void *info, NavCallBackUserData callBackUD, NavFilterModes filterMode ) { LSItemInfoRecord lsInfoRec; FSRef fsRef; OSStatus status; static Boolean applicationFSRefInitialized; static FSRef applicationFSRef; Boolean canViewItem = false; if ( theItem->descriptorType == typeFSRef ) { status = AEGetDescData( theItem, &fsRef, sizeof(fsRef) ); require_noerr( status, CantGetFSRef ); status = LSCopyItemInfoForRef( &fsRef, kLSRequestAllInfo, &lsInfoRec ); // Ask LaunchServices for information about the item require( (status == noErr) || (status == kLSApplicationNotFoundErr), LaunchServicesError ); if ( applicationFSRefInitialized == false ) // First time this routine ir run, we locate our application bundle { ProcessSerialNumber psn = { 0, kCurrentProcess }; GetProcessBundleLocation( &psn, &applicationFSRef ); // Save the reference in a static applicationFSRefInitialized = true; } if ( (lsInfoRec.flags & kLSItemInfoIsContainer) != 0 ) // If it's a folder, make it selectable canViewItem = true; else status = LSCanRefAcceptItem( &fsRef, &applicationFSRef, kLSRolesViewer, kLSAcceptDefault, &canViewItem ); // Can this application "view" this file? } LaunchServicesError: CantGetFSRef: return( canViewItem ); } static OSStatus OpenDocuments( AEDescList docList ) { long index; FSRef fsRef; CFStringRef fileName; WindowRef window = NULL; long count = 0; OSStatus status = AECountItems( &docList, &count ); require_noerr( status, CantGetCount ); for( index = 1; index <= count; index++ ) { if ( (status = AEGetNthPtr( &docList, index, typeFSRef, NULL, NULL, &fsRef, sizeof(FSRef), NULL) ) == noErr ) { status = DoNewWindow( &window ); // Create a new (Hidden) window require_noerr( status, CantCreateWindow ); status = LSCopyDisplayNameForRef( &fsRef, &fileName ); // Get the name of the file the Finder displays (may not include file extension) require_noerr( status, CantGetName ); SetWindowTitleWithCFString( window, fileName ); // Set the Window title status = DisplayTextFileInWindow( window, &fsRef ); if ( status == noErr ) ShowWindow( window ); // The window was created hidden so show it else DisposeWindow( window ); } } CantGetName: CantCreateWindow: CantGetCount: return( status ); } #pragma mark - #pragma mark • Utilities • // Utility routine to synchronously send a basic "kEventClassCommand / kEventCommandProcess" CarbonEvent to the application target static void SendCommandProcessEvent( UInt32 commandID ) { HICommand command; EventRef event; BlockZero( &command, sizeof(command) ); command.commandID = commandID; (void) CreateEvent( NULL, kEventClassCommand, kEventCommandProcess, GetCurrentEventTime(), kEventAttributeUserEvent, &event ); (void) SetEventParameter( event, kEventParamDirectObject, typeHICommand, sizeof(command), &command ); (void) SendEventToApplication( event ); (void) ReleaseEvent( event ); } static OSStatus GetControlBySigAndID( WindowRef window, OSType signature, SInt32 id, ControlRef *control ) { ControlID controlID = { signature, id }; return( GetControlByID( window, &controlID, control ) ); } static OSStatus HIViewFindBySigAndID( HIViewRef inStartView, OSType signature, SInt32 id, HIViewRef *outControl ) { HIViewID hiViewID = { signature, id }; return( HIViewFindByID( inStartView, hiViewID, outControl ) ); } static TXNObject GetTXNObjectBySigAndID( WindowRef window, OSType signature, SInt32 id ) { HIViewRef hiTextView; TXNObject txnObject = NULL; if ( window != NULL ) if ( HIViewFindBySigAndID( HIViewGetRoot(window), signature, id, &hiTextView ) == noErr ) if ( hiTextView != NULL ) txnObject = HITextViewGetTXNObject( hiTextView ); return( txnObject ); } /***************************************************** * * ExecuteCompiledAppleScriptEvent( AEDesc *scriptData, AppleEvent *theEvent, AEDesc *resultData ) * * Purpose: Generic routine to execute our AppleScriptEvent, passing parameters to an * AppleScript running inside my application * * Notes: http://developer.apple.com/qa/qa2001/qa1111.html * * Inputs: scriptData - Reference to the AppleScript to be executed * theEvent - text parameter to our AppleScript as an AppleEvent * resultData - result from script * * Returns: OSStatus - error code (0 == no error) */ OSStatus ExecuteCompiledAppleScriptEvent( AEDesc *scriptData, AppleEvent *theEvent, AEDesc *resultData ) { OSStatus err; ComponentInstance theComponent = NULL; OSAID contextID = kOSANullScript; OSAID resultID = kOSANullScript; theComponent = OpenDefaultComponent( kOSAComponentType, typeAppleScript ); // Open the scripting component if ( theComponent == NULL ) { err = paramErr; goto Bail; } err = OSALoad( theComponent, scriptData, kOSAModeNull, &contextID ); // Compile the script into a new context require_noerr( err, Bail ); err = OSAExecuteEvent( theComponent, theEvent, contextID, kOSAModeNull, &resultID ); // Run the script if ( resultData != NULL ) // Collect the results - if any { AECreateDesc( typeNull, NULL, 0, resultData ); if ( err == errOSAScriptError ) OSAScriptError( theComponent, kOSAErrorMessage, typeChar, resultData ); else if ( (err == noErr) && (resultID != kOSANullScript) ) OSADisplay(theComponent, resultID, typeChar, kOSAModeNull, resultData); } Bail: if ( contextID != kOSANullScript ) OSADispose( theComponent, contextID ); if ( resultID != kOSANullScript ) OSADispose( theComponent, resultID ); if ( theComponent != NULL ) CloseComponent( theComponent ); return( err ); } #pragma mark - #pragma mark • Specialized Routines • static OSStatus DoSomething() { DebugStr( "\pDoSomething Was Called\n" ); return( noErr ); } // This utility routine takes printf style arguments and puts the resulting text in the HITextView ( 'HITv', 0 ) within the passed in window. static void Wprintf( WindowRef window, char const *fmt, ... ) { char s[4096]; va_list args; TXNObject txnObject; if ( window == NULL ) return; va_start( args, fmt ); (void) vsprintf( s, fmt, args ); va_end( args ); txnObject = GetTXNObjectBySigAndID( window, 'HITv', 0 ); TXNSetData( txnObject, kTXNTextData, s, strlen(s), kTXNUseCurrentSelection, kTXNUseCurrentSelection ); return; } // Return the FSRef to the AppleScripts directory within our bundle static OSStatus GetAppleScriptsFolderFSRef( FSRef *fsRef) { Boolean successful = false; CFURLRef urlRef1 = NULL; CFURLRef urlRef2 = NULL; urlRef1 = CFBundleCopyResourcesDirectoryURL( CFBundleGetMainBundle() ); // Get URL to our bundles "Resources" directory require( urlRef1 != NULL , Bail ); urlRef2 = CFURLCreateCopyAppendingPathComponent( NULL, urlRef1, CFSTR("AppleScripts"), true ); // Append "AppleScripts" onto the URL, location of our AppleScripts require( urlRef1 != NULL , Bail ); successful = CFURLGetFSRef( urlRef2, fsRef ); // Convert the CFURL into an FSRef to be returned if ( urlRef1 != NULL ) CFRelease( urlRef1 ); if ( urlRef2 != NULL ) CFRelease( urlRef2 ); Bail: return( successful == false ); } static OSStatus DisplayTextFileInWindow( WindowRef window, FSRef *fsRef ) { OSStatus status; TXNObject txnObject; FSSpec fsSpec; CFURLRef cfURL = NULL; require( (fsRef != NULL) && (window != NULL), Bail ); txnObject = GetTXNObjectBySigAndID( window, 'HITv', 0 ); require( txnObject != NULL, CantGetTXNObject ); cfURL = CFURLCreateFromFSRef( NULL, fsRef ); // Create a CFURL from the passed in FSRef require( cfURL != NULL, CantCreateURL ); status = TXNSetDataFromCFURLRef( txnObject, cfURL, kTXNStartOffset, kTXNEndOffset ); // url will be stored by MLTE require_noerr( status, CantSetTXN ); status = FSGetCatalogInfo( fsRef, kFSCatInfoNone, NULL, NULL, &fsSpec, NULL ); // Need the FSSpec, since SetWindowProxy requires it require_noerr( status, CantGetFSSpec ); SetWindowProxyFSSpec( window, &fsSpec ); // The following lines deal with current shortcomings of the HITextView TXNRevert( txnObject ); // The change count is not set to 0 as it should, a call to TXNRevert workarounds the problem TXNSetSelection( txnObject, kTXNEndOffset, kTXNEndOffset ); TXNShowSelection( txnObject, true ); // The HIScrollView scroll bars don't reflect the current size of the HITextView, a couple of calls to Set/Show selection workaround the problem TXNSetSelection( txnObject, kTXNStartOffset, kTXNStartOffset ); TXNShowSelection( txnObject, true ); // The HIScrollView scroll bars don't reflect the current size of the HITextView, a couple of calls to Set/Show selection workaround the problem CantGetFSSpec: CantSetTXN: CantCreateURL: if ( cfURL != NULL ) CFRelease( cfURL ); CantGetTXNObject: Bail: return( status ); } /***************************************************** * * RunAppleScript( FSRef *scriptFSRef, char *textParameter ) * * Purpose: Runs an AppleScript with one text parameter as input. * CreateMessageEvent, and therefore RunAppleScript, assumes the AppleScript has a * subroutine entry titled "applescriptentry" and accepts one TEXT parameter. * * Inputs: scriptFSRef - FSRef to our AppleScript * textParameter - text parameter to our AppleScript * * Returns: OSStatus - error code (0 == no error) */ static OSStatus RunAppleScript( FSRef *scriptFSRef, char *textParameter ) { OSStatus err; AppleEvent aeParameter; AEDesc scriptData; short refNum; FSCatalogInfo catalogInfo; Handle h = NULL; refNum = FSOpenResFile( scriptFSRef, fsRdPerm ); // Older (Mac OS 8/9) scripts store their data in the 'scpt' (1) resource if ( refNum != -1 ) { h = Get1IndResource( 'scpt', 1 ); if( h != NULL ) DetachResource( h ); // Detach the handle before closing the resource CloseResFile( refNum ); } if ( h == NULL ) { err = FSGetCatalogInfo( scriptFSRef, kFSCatInfoDataSizes, &catalogInfo, NULL, NULL, NULL ); // Get the size of the script require_noerr( err, Bail ); err = FSOpenFork( scriptFSRef, 0, NULL, fsRdPerm, &refNum ); // Open the data fork read only require_noerr( err, Bail ); h = NewHandle( catalogInfo.dataLogicalSize ); err = FSReadFork( refNum, fsFromStart, 0, catalogInfo.dataLogicalSize, *h, NULL ); // Read the script into our handle (void) FSCloseFork( refNum ); // Close the file reference } err = CreateMessageEvent( &aeParameter, textParameter ); // Create the AppleEvent, and use the Apple event to call the script's subroutine require_noerr( err, Bail ); err = AECreateDesc( typeOSAGenericStorage, *h, GetHandleSize(h), &scriptData ); // Load the compiled script into an AEDesc of type typeOSAGenericStorage require_noerr( err, Bail ); err = ExecuteCompiledAppleScriptEvent( &scriptData, &aeParameter, NULL ); // "Generic" routine to execute our AppleScript Bail: if ( h != NULL ) DisposeHandle( h ); return( err ); } // http://developer.apple.com/qa/qa2001/qa1111.html // Creates an AppleEvent with one text parameter. We leave it up to the AppleScript // to further parse the text parameter into potentially more parameters. static OSStatus CreateMessageEvent( AppleEvent *theEvent, char *parameter ) { OSStatus err; ProcessSerialNumber psn = {0, kCurrentProcess}; err = AEBuildAppleEvent( 'ascr', kASSubroutineEvent, typeProcessSerialNumber, (Ptr) &psn, sizeof(psn), kAutoGenerateReturnID, kAnyTransactionID, theEvent, NULL, "'----':[TEXT(@)]," // One TEXT pointer parameter "'snam':TEXT(@)", // The keyASSubroutineName ('snam') parameter must contain the name of the subroutine that is being called with every letter converted to lowercase. For example, if name of the subroutine in your script is "GetDocumentSize", then the string provided in the keyASSubroutineName parameter should be "getdocumentsize". parameter, "applescriptentry"); // The entry routine whithin the AppleScript return( err ); }